package com.xingda.packing.minitor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xingda.packing.config.ThreadLocalConfig;
import com.xingda.packing.domain.CacheLocation;
import com.xingda.packing.domain.PackProductionLine;
import com.xingda.packing.minitor.dto.PkCacheLocationDto;
import com.xingda.packing.minitor.dto.PkCacheLocationUpdateDto;
import com.xingda.packing.minitor.dto.UserInfo;
import com.xingda.packing.minitor.entity.PkCacheLocation;
import com.xingda.packing.minitor.entity.PkWheel;
import com.xingda.packing.minitor.mapper.PkCacheLocationMapper;
import com.xingda.packing.minitor.mapper.PkWheelMapper;
import com.xingda.packing.minitor.service.IPkCacheLocationService;
import com.xingda.packing.minitor.service.IPkWheelService;
import com.xingda.packing.minitor.service.IpkLogService;
import com.xingda.packing.plc.service.PlcDirectiveService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author anxiaoning
 * @since 2021-07-03
 */
@Service
public class PkCacheLocationServiceImpl extends ServiceImpl<PkCacheLocationMapper, PkCacheLocation> implements IPkCacheLocationService {
    @Resource
    PkWheelMapper pkWheelMapper;
    @Resource
    PackProductionLine packProductionLine;
    @Resource
    private IPkWheelService pkWheelService;
    @Resource
    private ThreadLocalConfig threadLocalConfig;
    @Resource
    private IpkLogService ipkLogService;
    @Resource
    private PkCacheLocationMapper pkCacheLocationMapper;
    @Resource
    private PlcDirectiveService plcDirectiveService;
    @Value("${spring.profiles.active}")
    private String env;

    @Override
    public List<PkCacheLocationDto> getPkCacheLocation(Integer area) {
        List<PkCacheLocation> pkCacheLocations;
        if (area == 1) {
            pkCacheLocations = this.lambdaQuery().between(PkCacheLocation::getId, 1, packProductionLine.getCacheArea().getLeftMaxNo()).orderByDesc(PkCacheLocation::getLocationNo).list();
        } else if (area == 2) {
            pkCacheLocations = this.lambdaQuery().between(PkCacheLocation::getId, packProductionLine.getCacheArea().getLeftMaxNo() + 1, packProductionLine.getCacheArea().getLeftMaxNo() + packProductionLine.getCacheArea().getRightMaxNo()).orderByAsc(PkCacheLocation::getLocationNo).list();
        } else {
            pkCacheLocations = this.lambdaQuery().orderByAsc(PkCacheLocation::getLocationNo).list();
        }
        List<Integer> ids = pkCacheLocations.stream().map(PkCacheLocation::getWheelId).collect(Collectors.toList());

        List<PkWheel> wheels = this.pkWheelService.lambdaQuery().in(PkWheel::getId, ids).list();

        List<PkCacheLocationDto> dtos = new ArrayList<>();

        pkCacheLocations.forEach(pkCacheLocation -> {
            PkCacheLocationDto dto = new PkCacheLocationDto();
            BeanUtils.copyProperties(pkCacheLocation, dto);
            if (dto.getWheelId() != null) {
                PkWheel wheel = wheels.stream().filter(w -> dto.getWheelId().compareTo(w.getId()) == 0).findAny().orElse(null);
                dto.setWheel(wheel);
                if (wheel != null) {
                    dto.setWheelTag(wheel.getWheelTag());
                    dto.setBarCode(wheel.getBarCode());
                }
            }
            dtos.add(dto);
        });
        return dtos;
    }

    @Override
    public List<List<PkCacheLocationDto>> getSortCacheLocation(Integer area) {
        List<List<PkCacheLocationDto>> list = new ArrayList<>();
        List<PkCacheLocationDto> cacheList = getPkCacheLocation(area);
        List<PkCacheLocationDto> locations1 = new ArrayList<>();
        List<PkCacheLocationDto> locations2 = new ArrayList<>();
        if (cacheList.size() == 54) {
            for (PkCacheLocationDto location : cacheList) {
                if (location.getLocationNo() % 2 == 0) {
                    locations1.add(location);
                } else {
                    locations2.add(location);
                }
            }
            list.add(locations2);
            list.add(locations1);
            return list;
        } else {
            List<PkCacheLocationDto> locations3 = new ArrayList<>();
            for (PkCacheLocationDto location : cacheList) {
                if (location.getLocationNo() < 31) {
                    if (location.getLocationNo() % 2 == 0) {
                        locations3.add(location);
                    } else {
                        locations2.add(location);
                    }
                } else {
                    if (location.getLocationNo() % 3 == 0) {
                        locations3.add(location);
                    } else if (location.getLocationNo() % 3 - 2 == 0) {
                        locations2.add(location);
                    } else {
                        locations1.add(location);
                    }
                }
            }
            list.add(locations1);
            list.add(locations2);
            list.add(locations3);
            return list;
        }
    }

    @Transactional
    @Override
    public boolean cleanPkCacheLocation(Integer locationNo, Integer area) {
        boolean flag = false;
        LambdaQueryWrapper<PkCacheLocation> locationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        locationLambdaQueryWrapper.eq(PkCacheLocation::getLocationNo, locationNo);
        locationLambdaQueryWrapper.eq(PkCacheLocation::getArea, area);
        PkCacheLocation location = pkCacheLocationMapper.selectOne(locationLambdaQueryWrapper);
        if (Objects.nonNull(location.getWheelId())) {
            UpdateWrapper<PkCacheLocation> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("wheel_id", null);
            updateWrapper.eq("location_no", locationNo);
            updateWrapper.eq("area", area);
            flag = this.update(updateWrapper);
            pkWheelMapper.deleteById(location.getWheelId());
        }
        // 机器人自动放置清除缓存位
        packProductionLine.getCacheArea().removeWheel(location.getLocationNo(), area);
        UserInfo userInfo = threadLocalConfig.get();
        String op = userInfo.getOperation();
        String operation = area == 1 ? "左收线" : "右收线";
        userInfo.setOperation(operation + op);
        ipkLogService.saveLog(userInfo);
        threadLocalConfig.remove();
        if (env.startsWith("xd-prod")) {
            //PLC 删除单个
            if (!plcDirectiveService.clearCacheLocationNo(locationNo, area)) {
                flag = false;
            }
            //删除完成重置
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            plcDirectiveService.resetCacheStatus(area);
        }
        return flag;
    }

    @Transactional
    @Override
    public boolean cleanAll(Integer area) {
        boolean result = true;
        List<PkCacheLocation> pkCacheLocations;
        if (area == 1) {
            pkCacheLocations = this.lambdaQuery().between(PkCacheLocation::getId, 1, packProductionLine.getCacheArea().getLeftMaxNo()).list();
        } else {
            pkCacheLocations = this.lambdaQuery().between(PkCacheLocation::getId, packProductionLine.getCacheArea().getLeftMaxNo() + 1, packProductionLine.getCacheArea().getLeftMaxNo() + packProductionLine.getCacheArea().getRightMaxNo()).list();
        }
        if (pkCacheLocations != null && !pkCacheLocations.isEmpty()) {
            //清除内存中的缓存位
            pkCacheLocations.forEach(cacheLocation -> {
                if (cacheLocation.getWheelId() != null) {
                    UpdateWrapper<PkCacheLocation> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.set("wheel_id", null);
                    updateWrapper.lambda().eq(PkCacheLocation::getId, cacheLocation.getId());
                    this.update(updateWrapper);
                    pkWheelMapper.deleteById(cacheLocation.getWheelId());
                }
            });
            packProductionLine.getCacheArea().getLocationList(area).clear();
            packProductionLine.getCacheArea().initStatus(area);
        }
        //PLC 删除所有
        UserInfo userInfo = threadLocalConfig.get();
        String op = userInfo.getOperation();
        String operation = area == 1 ? "左收线" : "右收线";
        userInfo.setOperation(operation + op);
        ipkLogService.saveLog(userInfo);
        threadLocalConfig.remove();
        if (env.startsWith("xd-prod")) {
            result = plcDirectiveService.clearCacheLocationNo(100, area);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            plcDirectiveService.resetCacheStatus(area);
        }
        return result;
    }

    @Override
    public PkCacheLocationDto getPkCacheLocationById(int id) {
        PkCacheLocation pkCacheLocation = this.getById(id);
        PkCacheLocationDto dto = new PkCacheLocationDto();
        BeanUtils.copyProperties(pkCacheLocation, dto);
        return dto;
    }

    @Transactional
    @Override
    public void updatePkCacheLocationBy(PkCacheLocationUpdateDto pkCacheLocationUpdateDto) {
        Integer id = pkCacheLocationUpdateDto.getId();
        UpdateWrapper<PkCacheLocation> updateWrapper = new UpdateWrapper<>();
        Integer enable = pkCacheLocationUpdateDto.getEnable();
        updateWrapper.set("enable", enable);
        updateWrapper.eq("id", id);
        this.update(updateWrapper);
        PkCacheLocation pkCacheLocation = this.getById(id);
        int area = 1;
        if (id > packProductionLine.getCacheArea().getLeftMaxNo()) {
            area = 2;
        }
        Optional<CacheLocation> opt = packProductionLine.getCacheArea().getLocation(pkCacheLocation.getLocationNo(), area);
        if (opt.isPresent()) {
            CacheLocation cacheLocation = opt.get();
            cacheLocation.setEnable(enable);
        }
        UserInfo userInfo = threadLocalConfig.get();
        String operation = "左收线";
        if (id > packProductionLine.getCacheArea().getLeftMaxNo()) {
            operation = "右收线";
            id = id - packProductionLine.getCacheArea().getLeftMaxNo();
        }
        userInfo.setOperation(operation + "更新缓存位:" + id);
        ipkLogService.saveLog(userInfo);
        threadLocalConfig.remove();
    }
}
